package core.reports;

import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Iterator;

import core.Amount;
import core.Container;
import core.Item;
import core.ItemManager;
import core.Product;
import core.ProductGroup;
import core.ProductManager;
import core.RootStorageUnit;
import core.StorageUnit;
import core.exception.InvalidConversionException;

/**
 * This implementation of IReportVisitor generates the first part of N Month Supply Report
 * @author Royce
 *
 */
public class NMonthSupplyVisitor2 implements IReportVisitor 
{
	private IReportBuilder _builder;
	private int _months;
	private TraversingType _type;
	private ArrayList<Item> _items;
	private StorageUnit _currentSU;
	
	public NMonthSupplyVisitor2(IReportBuilder builder, int months) throws IOException
	{
		_months = months;
		_type = TraversingType.PREORDER;
		setBuilder(builder);
		_items = new ArrayList<Item>();
		_currentSU = null;
	}
	/**
	 * Sets the report Builder that this visitor will use.
	 * @param builder any implementation of IReportBuilder.
	 * @throws IOException 
	 */
	private void setBuilder(IReportBuilder builder) throws IOException 
	{
		_builder = builder;
		_builder.startTable("Product Groups", 4);
		_builder.addCell("Product Group");
		_builder.addCell("Storage Unit");
		_builder.addCell(_months + "-Month Supply");
		_builder.addCell("Current Supply");
	}

	/**
	 * Called when the Root Storage Unit is visited.
	 * @param rsu the RootStorageUnit.
	 */
	@Override
	public void visitRoot(RootStorageUnit rsu) 
	{
		//do nothing
	}

	/**
	 * Called when a Storage Unit is visited
	 * @param su a reference to the visited StorageUnit
	 */
	@Override
	public void visitStorageUnit(StorageUnit su)
	{
		_currentSU = su;
	}
	
	private String getAmountString(Amount amt)
	{
		DecimalFormat df = new DecimalFormat("#0.##");
		String theString = df.format(amt.getQuantity()) + " " + amt.getUnit();
		return  theString;
	}

	/**
	 * Called when a Product Group is visited
	 * @param pg a reference to the visited ProductGroup
	 */
	@Override
	public void visitProductGroup(ProductGroup pg) 
	{
		//TODO: find out if this can be done without being recursive
		_items = getItemsRecursive(pg);
		Amount currentSupply = new Amount(0, pg.getThreeMonthSupply().getUnit());
		for (Item i: _items)
		{
			try {
				currentSupply.add(i.getAmount());
			} catch (InvalidConversionException e) {
				//do nothing
			}
		}
		
		try 
		{
			Amount nMoSupply = calculateSupply(pg);
			if (currentSupply.getQuantity() < nMoSupply.getQuantity())
			{
				_builder.addCell(pg.getName());
				_builder.addCell(_currentSU.getName());
				_builder.addCell(getAmountString(nMoSupply));
				_builder.addCell(getAmountString(currentSupply));
			}
		} 
		catch (IOException e) 
		{
			//this shouldn't happen
		}
		finally
		{
			_items = new ArrayList<Item>();
		}
	}
	
	private ArrayList<Item> getItemsRecursive(ProductGroup p) {
		ArrayList<Item> items = new ArrayList<Item>();
		if (p == null) return items;

		Iterator<Item> itemIter = p.getItems();
		if(itemIter != null) {
			while (itemIter.hasNext()) {
				items.add(itemIter.next());
			}
		}
		
		Iterator<Container> cIter = p.getChildContainers();
		if (cIter == null) return items;
		while (cIter.hasNext()) {
			items.addAll(getItemsRecursive((ProductGroup)cIter.next()));
		}
		
		return items;
	}

	private Amount calculateSupply(ProductGroup pg) 
	{
		float qty = pg.getThreeMonthSupply().getQuantity();
		qty *= _months;
		qty /= 3.0f;
		return new Amount (qty, pg.getThreeMonthSupply().getUnit());
	}
	/**
	 * Called when a Product is visited
	 * @param product a reference to the visited Product
	 */
	@Override
	public void visitProduct(Product product) {
		//do nothing
	}

	/**
	 * Called when an Item is visited
	 * @param item a reference to the visited Item
	 */
	@Override
	public void visitItem(Item item) {
		if (!item.isUsed())
		{
			_items.add(item);
		}
	}

	@Override
	public TraversingType getType() {
		return _type;
	}

	@Override
	public void visitProductManager(ProductManager pm) {
		//do nothing
	}

	@Override
	public void visitItemManager(ItemManager im) {
		//do nothing
	}
	@Override
	public void onDone() {
		// TODO Auto-generated method stub
		
	}
}
